package gnssio

import (
	"dgo/goutils/gis"
	"dgo/goutils/utils"
)

type CommNMEAGetter struct {
	listeners       *utils.SafeList
	inner_data_comm I_Comm
	nmeaPack        *utils.SEBufPack
}

func NewCommNMEAGetter() *CommNMEAGetter {
	rval := &CommNMEAGetter{
		listeners: utils.NewSafeList(),
		nmeaPack:  utils.NewSEBufPack(1024),
	}
	rval.nmeaPack.SetSEBuf([]byte("$"), []byte("*"))
	return rval
}

func (this *CommNMEAGetter) dispatchBuffer(buf []byte, len int) {
	this.listeners.ForEach(func(val interface{}) {
		val.(I_CommListener).OnReceive(this, buf, len)
	})
}

func (this *CommNMEAGetter) SetInnerDataComm(data_comm I_Comm) {
	if this.inner_data_comm != data_comm {
		if this.inner_data_comm != nil {
			this.inner_data_comm.RemoveListener(this)
		}
		this.inner_data_comm = data_comm
		this.inner_data_comm.AddListener(this)
	}
}

func (this *CommNMEAGetter) OnReceive(sender I_Comm, buf []byte, buflen int) {
	if buflen == 0 {
		return
	}

	dbuf := buf[:buflen]

	l := 0
	for {
		r := this.nmeaPack.InputBuf(dbuf[l:], 0)
		if r == 1 {
			tmpL := l + this.nmeaPack.GetDecodeL()
			tmpL += this.nmeaPack.ForceAppend(buf[tmpL:], 2)

			nmeaStr := string(this.nmeaPack.GetRawBuf())
			nmea := gis.NewNMEA()
			nmea.ParseText(nmeaStr)
			if nmea.IsOK {
				l = tmpL
				this.dispatchBuffer(this.nmeaPack.GetRawBuf(), this.nmeaPack.GetSize())
			} else {
				l += 1
			}
			this.nmeaPack.Reset()
		} else if r == 0 {
			// need more
			l += this.nmeaPack.GetDecodeL()
		} else {
			l += this.nmeaPack.GetDecodeL()
			this.nmeaPack.Reset()
		}

		if l >= len(dbuf) {
			break
		}
	}
}

func (this *CommNMEAGetter) OnConnect(sender I_Comm) {

}

func (this *CommNMEAGetter) OnDisconnect(sender I_Comm) {

}

// =================================================================
func (this *CommNMEAGetter) Start() {
	if this.inner_data_comm != nil {
		this.inner_data_comm.Start()
	}
}

func (this *CommNMEAGetter) Stop() {
	if this.inner_data_comm != nil {
		this.inner_data_comm.Stop()
	}
}

func (this *CommNMEAGetter) Send(buf []byte, len int) int {
	return this.inner_data_comm.Send(buf, len)
}

func (this *CommNMEAGetter) AddListener(event I_CommListener) {
	if this.listeners.Exists(event) {
		utils.Log.Warn("I_CommListener已经存在请勿重复侦听")
		return
	}
	this.listeners.Add(event)
}

func (this *CommNMEAGetter) RemoveListener(event I_CommListener) {
	this.listeners.Remove(event)
}
